// ============================== 导入依赖 ============================== //

import CORE from '../UTIL'
import util from './util'

// ============================== 状态集 ============================== //

const state = {
  // —————————————————————————————— 数据 —————————————————————————————— //

  /**
   * 接口
   */
  API: {
    ...util.API,
    validTreeParam(treeParam, state, root) {
      return true
    },
    transTreeParam(treeParam, context) {
      return treeParam
    },
    getTree: null,
    transTree(arr, context) {
      return arr
    },
  },

  /**
   * 映射
   */
  MAP: {
    WORD: '', // 词语 (初始常量，不可更新)

    GET: null, // 获取 (为 null 取 CORE.MAP.TIP_XXX，可设置为 '')
    TREE: null, // 结构树 (为 null 取 CORE.MAP.TIP_XXX，可设置为 '')

    tipTree: '', // 结构树提示 (有值时直接使用，无值时拼接生成)
  },

  /**
   * 字典
   */
  DICT: {
    //
  },

  /**
   * 初始配置
   */
  INIT_CONFIG: {
    /**
     * 是否为单例结构树
     *
     * true  单例结构树 (只在原有数组上增改删)
     * false 普通结构树 (每次 setTree 生成新数组)
     */
    IS_SINGLE_TREE: false,

    /**
     * 结构树字典层级 (为 0 表示不限制)
     */
    TREE_DICT_LEVEL: 0,
  },

  /**
   * 结构树字段 ( 可增加，示例 ['children', 'id', 'name', 'other', (item) => () => item.status !== 1] )
   */
  TREE_FIELD: ['children', 'id', 'name'],

  /**
   * 结构树参数
   */
  treeParam: { page: 1 },

  /**
   * 结构树
   */
  tree: [],

  // —————————————————————————————— 弹窗 —————————————————————————————— //

  /**
   * 弹窗可见
   */
  treeVisible: false,

  // —————————————————————————————— 开关 —————————————————————————————— //

  /**
   * 远程结构树开关
   */
  needTree: false,

  /**
   * 结构树就绪开关
   */
  readyTree: false,
}

// ============================== 计算属性 ============================== //

const getters = {
  /**
   * 结构树字典 [[children, id, name, other], [children, id, name, other]]
   */
  treeDict: ({ tree, TREE_FIELD, INIT_CONFIG }) => {
    return transTreeDict([], tree, TREE_FIELD, INIT_CONFIG.TREE_DICT_LEVEL)
  },

  /**
   * 结构树映射 { id1: { ... }, id2: { ... } }
   */
  treeMap: ({ tree, TREE_FIELD }) => {
    return transTreeMap({}, tree, TREE_FIELD)
  },
}

// ============================== 同步更新 ============================== //

const mutations = {
  // —————————————————————————————— 设置 —————————————————————————————— //

  /**
   * 设置结构树
   */
  setTree(state, tree) {
    setStateTree(state, state.tree, tree)
  },

  // —————————————————————————————— 弹窗 —————————————————————————————— //

  /**
   * 打开结构树弹窗
   */
  openTree(state) {
    state.treeVisible = true
  },

  /**
   * 关闭结构树弹窗
   */
  closeTree(state) {
    state.treeVisible = false
  },

  // —————————————————————————————— 监听 —————————————————————————————— //

  /**
   * 开始远程结构树
   */
  startTree(state) {
    if (state.API.validTreeParam(state.treeParam, state, this)) {
      util.start('Tree', state)
    } else {
      setStateTree(state, state.tree, []) // 重置结构树
    }
  },

  /**
   * 完成远程结构树
   */
  completeTree(state, data) {
    let msgSuccess = ''
    if (CORE.isArray(data)) {
      if (CORE.isArray(data[0]) && CORE.isString(data[1])) {
        setStateTree(state, state.tree, data[0]) // 设置结构树
        msgSuccess = data[1] // 成功消息
      } else {
        setStateTree(state, state.tree, data) // 设置结构树
      }
    }
    util.complete('Tree', state, msgSuccess)
  },

  /**
   * 终止远程结构树
   */
  stopTree(state, e) {
    setStateTree(state, state.tree, []) // 重置结构树
    util.stop('Tree', state, e)
  },
}

// ============================== 异步调用 ============================== //

const actions = {
  // —————————————————————————————— 结构树 —————————————————————————————— //

  async remoteTree(context) {
    const { state: { API, MAP, treeParam } } = context
    const TIP = API.transTip(MAP.tipTree, this.state.API) // 拼上根模块 API 的菜单

    const myParam = await API.transTreeParam(treeParam, context)

    if (API.getTree) {
      const arr = await API.getTree(myParam, TIP)
      return API.transTree(arr, context)
    }

    if (API.getList) {
      const [, arr] = await API.getList(myParam, TIP)
      return API.transTree(arr, context)
    }
  },
}

// ============================== 导出仓库 ============================== //

export default { state, getters, mutations, actions }

// ============================== 内部方法 ============================== //

const setTreeParent = (tree, field, parentId, parentName = '', parentIdList = [], parentNameList = []) => {
  tree.forEach((item) => {
    const [children, id, name] = [item[field[0]] || [], item[field[1]] || '', item[field[2]] || '']
    const [idList, nameList] = [[...parentIdList, id], [...parentNameList, name]]

    // 如有同名旧属性，且与新值不等，则记录旧值
    if (item.parentId && item.parentId !== parentId) item.parentIdInit = item.parentId
    if (item.parentName && item.parentName !== parentName) item.parentNameInit = item.parentName
    if (item.idList && JSON.stringify(item.idList) !== JSON.stringify(idList)) item.idListInit = item.idList
    if (item.nameList && JSON.stringify(item.nameList) !== JSON.stringify(nameList)) item.nameListInit = item.nameList

    // 更新四个新值
    Object.assign(item, { parentId, parentName, idList, nameList })

    // 递归调用
    setTreeParent(children, field, id, name, idList, nameList)
  })
  return tree
}

const setStateTree = (state, TREE, tree) => {
  // 普通结构树
  if (!state.INIT_CONFIG.IS_SINGLE_TREE) {
    state.tree = setTreeParent(tree || [], state.TREE_FIELD)
    return
  }

  // 单例结构树
  const list = (tree || []).map((item) => {
    const matched = TREE.find(({ id }) => item.id === id) || {}
    const children = matched.children || []
    delete matched.children
    setStateTree(state, children, item.children)
    return Object.assign(matched, item)
  })

  TREE.splice(0, TREE.length, ...list)
}

// ============================== 转换方法 ============================== //

/**
 * 转换结构树字典
 *
 * @param {Array} treeDict 结构树字典
 * @param {Array} tree 结构树
 * @param {Array} field 键名
 * @param {Number} limit 层级限制
 * @param {Number} level 当前层级
 */
export const transTreeDict = (treeDict, tree, field, limit = 0, level = 1) => {
  if (limit && level > limit) return []
  tree.forEach((item) => {
    const [children, id, name, ...other] = field.map((key, i) => {
      if (!i) return item[key] || []
      if (CORE.isFunction(key)) return key(item)
      return key ? item[key] : ''
    })
    const newChildren = []
    treeDict.push([newChildren, id, name, ...other])
    transTreeDict(newChildren, children, field, limit, level + 1)
  })
  return treeDict
}

/**
 * 转换结构树映射
 *
 * @param {Object} treeMap 结构树映射
 * @param {Array} tree 结构树
 * @param {Array} field 键名
 */
export const transTreeMap = (treeMap, tree, field) => {
  tree.forEach((item) => {
    const [children, id] = field.slice(0, 2).map((key, i) => item[key || ''] || (i ? '' : []))
    treeMap[id] = item
    transTreeMap(treeMap, children, field)
  })
  return treeMap
}
